#line 1 "parser.rl"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "parser.h"

/* define default callbacks */
static void 
esi_parser_default_start_cb( const void *data,
                             const char *name_start,
                             size_t name_length,
                             ESIAttribute *attributes,
                             void *user_data )
{
}
static void 
esi_parser_default_end_cb( const void *data,
                           const char *name_start,
                           size_t name_length,
                           void *user_data )
{
}
static void 
esi_parser_default_output_cp(const void *data,
                             size_t length,
                             void *user_data)
{
}
#ifdef DEBUG
static void debug_string( const char *msg, const char *str, size_t len )
{
  char *pstr = esi_strndup( str, len );
  printf( "%s :'%s'\n", msg, pstr );
  free( pstr );
}
#endif

static void esi_parser_echo_char( ESIParser *parser, char ch )
{
  parser->output_handler( (void*)&ch, 1, parser->user_data );
}

static void esi_parser_echo_buffer( ESIParser *parser )
{
//  debug_string( "echobuffer", parser->echobuffer, parser->echobuffer_index+1 );
  parser->output_handler( parser->echobuffer, parser->echobuffer_index+1, parser->user_data );
}

static void esi_parser_echobuffer_clear( ESIParser *parser )
{
  parser->echobuffer_index = -1;
}

static void esi_parser_concat_to_echobuffer( ESIParser *parser, char ch )
{
  parser->echobuffer_index++;

  if( parser->echobuffer_allocated <= parser->echobuffer_index ){
    // double the echobuffer size
    parser->echobuffer_allocated *= 2;
    parser->echobuffer = (char*)realloc( parser->echobuffer, parser->echobuffer_allocated );
  }
  parser->echobuffer[parser->echobuffer_index] = ch;
//  debug_string( "echo buffer", parser->echobuffer, parser->echobuffer_index+1 );
}

static void ltrim_pointer( const char **ptr, const char *bounds, size_t *len )
{
  // remove any spaces or = at the before the value
  while( isspace( **ptr ) ||
         **ptr == '=' ||
         **ptr == '"' ||
         **ptr == '<' ||
         **ptr == '\'' &&
         *len > 0 &&
         (*ptr != bounds) ){
    (*ptr)++;
    (*len)--;
  }
}

#line 198 "parser.rl"



#line 88 "parser.c"
static const int esi_start = 56;
static const int esi_first_final = 56;
static const int esi_error = -1;

static const int esi_en_main = 56;

#line 201 "parser.rl"

char *esi_strndup( const char *str, size_t len )
{
  char *s = (char*)malloc(sizeof(char)*(len+1));
  memcpy( s, str, len );
  s[len] = '\0';
  return s;
}

ESIAttribute *esi_attribute_new( const char *name, size_t name_length, const char *value, size_t value_length )
{
  ESIAttribute *attr = (ESIAttribute*)malloc(sizeof(ESIAttribute));
  attr->name = esi_strndup(name, name_length);
  attr->value = esi_strndup(value, value_length);
  attr->next = NULL;
  return attr;
}

ESIAttribute *esi_attribute_copy( ESIAttribute *attribute )
{
  ESIAttribute *head, *nattr;
  if( !attribute ){ return NULL; }

  // copy the first attribute
  nattr = esi_attribute_new( attribute->name, strlen( attribute->name ),
                             attribute->value, strlen( attribute->value ) );
  // save a pointer for return
  head = nattr;
  // copy next attributes
  attribute = attribute->next;
  while( attribute ) {
    // set the next attribute
    nattr->next = esi_attribute_new( attribute->name, strlen( attribute->name ),
                                     attribute->value, strlen( attribute->value ) );
    // next attribute
    nattr = nattr->next;
    attribute = attribute->next;
  }
  return head;
}

void esi_attribute_free( ESIAttribute *attribute )
{
  ESIAttribute *ptr;
  while( attribute ){
    free( attribute->name );
    free( attribute->value );
    ptr = attribute->next;
    free( attribute );
    attribute = ptr;
  }
}

ESIParser *esi_parser_new()
{
  ESIParser *parser = (ESIParser*)malloc(sizeof(ESIParser));
  parser->cs = esi_start;
  parser->mark = NULL;
  parser->overflow_data_size = 0;
  parser->overflow_data = NULL;

  /* allocate 1024 bytes for the echobuffer */
  parser->echobuffer_allocated = 1024;
  parser->echobuffer_index = -1;
  parser->echobuffer = (char*)malloc(sizeof(char)*parser->echobuffer_allocated);

  parser->attributes = NULL;
  parser->last = NULL;

  parser->start_tag_handler = esi_parser_default_start_cb;
  parser->end_tag_handler = esi_parser_default_end_cb;
  parser->output_handler = esi_parser_default_output_cp;

  return parser;
}
void esi_parser_free( ESIParser *parser )
{
  if( parser->overflow_data ){ free( parser->overflow_data ); }

  free( parser->echobuffer );
  esi_attribute_free( parser->attributes );

  free( parser );
}

void esi_parser_output_handler( ESIParser *parser, output_cb output_handler )
{
  parser->output_handler = output_handler;
}

int esi_parser_init( ESIParser *parser )
{
  int cs;
  
#line 190 "parser.c"
	{
	cs = esi_start;
	}
#line 295 "parser.rl"
  parser->prev_state = parser->cs = cs;
  return 0;
}

static int compute_offset( const char *mark, const char *data )
{
  if( mark ){
    return mark - data;
  }
  return -1;
}

int esi_parser_execute( ESIParser *parser, const char *data, size_t length )
{
  int cs = parser->cs;
  const char *p = data;
  const char *pe = data + length;

  if( length == 0 ){ return cs; }

  if( parser->overflow_data && parser->overflow_data_size > 0 ){

    // recompute mark, tag_text, attr_key, and attr_value since they all exist within overflow_data
    int mark_offset = compute_offset( parser->mark, parser->overflow_data );
    int tag_text_offset = compute_offset( parser->tag_text, parser->overflow_data );
    int attr_key_offset = compute_offset( parser->attr_key, parser->overflow_data );
    int attr_value_offset = compute_offset( parser->attr_value, parser->overflow_data );

//    debug_string("grow overflow buffer", parser->overflow_data, parser->overflow_data_size );

    parser->overflow_data = (char*)realloc( parser->overflow_data, sizeof(char)*(parser->overflow_data_size+length) );
    memcpy( parser->overflow_data+parser->overflow_data_size, data, length );

    p = parser->overflow_data + parser->overflow_data_size;
    
    // in our new memory space mark will now be
    parser->mark = ( mark_offset >= 0 ) ? parser->overflow_data + mark_offset : NULL;
    parser->tag_text = ( tag_text_offset >= 0 ) ? parser->overflow_data + tag_text_offset : NULL;
    parser->attr_key = ( attr_key_offset >= 0 ) ? parser->overflow_data + attr_key_offset : NULL;
    parser->attr_value = ( attr_value_offset >= 0 ) ? parser->overflow_data + attr_value_offset : NULL;
 
    data = parser->overflow_data;
    parser->overflow_data_size = length = length + parser->overflow_data_size;
    pe = data + length;

//    debug_string( "overflow", parser->overflow_data, parser->overflow_data_size );
  }

  if( !parser->mark ){
    parser->mark = p;
  }

//  printf( "cs: %d, ", cs );
//  debug_string( "data", data, length );

  
#line 251 "parser.c"
	{
	if ( p == pe )
		goto _out;
_resume:
	switch ( cs ) {
case 56:
	if ( (*p) == 60 )
		goto tr1;
	goto tr0;
case 0:
	if ( (*p) == 60 )
		goto tr1;
	goto tr0;
case 1:
	switch( (*p) ) {
		case 47: goto tr2;
		case 60: goto tr1;
		case 101: goto tr3;
	}
	goto tr0;
case 2:
	switch( (*p) ) {
		case 60: goto tr1;
		case 101: goto tr4;
	}
	goto tr0;
case 3:
	switch( (*p) ) {
		case 60: goto tr1;
		case 115: goto tr5;
	}
	goto tr0;
case 4:
	switch( (*p) ) {
		case 60: goto tr1;
		case 105: goto tr6;
	}
	goto tr0;
case 5:
	switch( (*p) ) {
		case 58: goto tr7;
		case 60: goto tr1;
	}
	goto tr0;
case 6:
	if ( (*p) == 60 )
		goto tr1;
	if ( 97 <= (*p) && (*p) <= 122 )
		goto tr8;
	goto tr0;
case 7:
	switch( (*p) ) {
		case 60: goto tr1;
		case 62: goto tr9;
	}
	if ( 97 <= (*p) && (*p) <= 122 )
		goto tr8;
	goto tr0;
case 8:
	switch( (*p) ) {
		case 60: goto tr1;
		case 115: goto tr10;
	}
	goto tr0;
case 9:
	switch( (*p) ) {
		case 60: goto tr1;
		case 105: goto tr11;
	}
	goto tr0;
case 10:
	switch( (*p) ) {
		case 58: goto tr12;
		case 60: goto tr1;
	}
	goto tr0;
case 11:
	if ( (*p) == 60 )
		goto tr1;
	if ( 97 <= (*p) && (*p) <= 122 )
		goto tr13;
	goto tr0;
case 12:
	switch( (*p) ) {
		case 32: goto tr14;
		case 47: goto tr15;
		case 60: goto tr1;
		case 62: goto tr16;
	}
	if ( (*p) > 13 ) {
		if ( 97 <= (*p) && (*p) <= 122 )
			goto tr13;
	} else if ( (*p) >= 9 )
		goto tr14;
	goto tr0;
case 13:
	switch( (*p) ) {
		case 32: goto tr17;
		case 45: goto tr18;
		case 47: goto tr19;
		case 60: goto tr1;
		case 62: goto tr20;
		case 95: goto tr18;
	}
	if ( (*p) < 65 ) {
		if ( 9 <= (*p) && (*p) <= 13 )
			goto tr17;
	} else if ( (*p) > 90 ) {
		if ( 97 <= (*p) && (*p) <= 122 )
			goto tr18;
	} else
		goto tr18;
	goto tr0;
case 14:
	switch( (*p) ) {
		case 32: goto tr17;
		case 45: goto tr18;
		case 47: goto tr19;
		case 60: goto tr1;
		case 95: goto tr18;
	}
	if ( (*p) < 65 ) {
		if ( 9 <= (*p) && (*p) <= 13 )
			goto tr17;
	} else if ( (*p) > 90 ) {
		if ( 97 <= (*p) && (*p) <= 122 )
			goto tr18;
	} else
		goto tr18;
	goto tr0;
case 15:
	switch( (*p) ) {
		case 45: goto tr18;
		case 60: goto tr1;
		case 61: goto tr21;
		case 95: goto tr18;
	}
	if ( (*p) < 65 ) {
		if ( 48 <= (*p) && (*p) <= 57 )
			goto tr18;
	} else if ( (*p) > 90 ) {
		if ( 97 <= (*p) && (*p) <= 122 )
			goto tr18;
	} else
		goto tr18;
	goto tr0;
case 16:
	switch( (*p) ) {
		case 32: goto tr22;
		case 34: goto tr23;
		case 39: goto tr23;
		case 60: goto tr1;
	}
	if ( 9 <= (*p) && (*p) <= 13 )
		goto tr22;
	goto tr0;
case 17:
	switch( (*p) ) {
		case 33: goto tr24;
		case 60: goto tr25;
		case 95: goto tr24;
		case 125: goto tr24;
	}
	if ( (*p) < 40 ) {
		if ( 35 <= (*p) && (*p) <= 38 )
			goto tr24;
	} else if ( (*p) > 90 ) {
		if ( 97 <= (*p) && (*p) <= 123 )
			goto tr24;
	} else
		goto tr24;
	goto tr0;
case 18:
	switch( (*p) ) {
		case 34: goto tr26;
		case 39: goto tr26;
		case 60: goto tr25;
		case 95: goto tr24;
		case 125: goto tr24;
	}
	if ( (*p) > 90 ) {
		if ( 97 <= (*p) && (*p) <= 123 )
			goto tr24;
	} else if ( (*p) >= 33 )
		goto tr24;
	goto tr0;
case 19:
	switch( (*p) ) {
		case 32: goto tr27;
		case 45: goto tr18;
		case 47: goto tr28;
		case 60: goto tr1;
		case 62: goto tr20;
		case 95: goto tr18;
	}
	if ( (*p) < 65 ) {
		if ( 9 <= (*p) && (*p) <= 13 )
			goto tr27;
	} else if ( (*p) > 90 ) {
		if ( 97 <= (*p) && (*p) <= 122 )
			goto tr18;
	} else
		goto tr18;
	goto tr0;
case 20:
	switch( (*p) ) {
		case 32: goto tr27;
		case 45: goto tr18;
		case 47: goto tr28;
		case 60: goto tr1;
		case 95: goto tr18;
	}
	if ( (*p) < 65 ) {
		if ( 9 <= (*p) && (*p) <= 13 )
			goto tr27;
	} else if ( (*p) > 90 ) {
		if ( 97 <= (*p) && (*p) <= 122 )
			goto tr18;
	} else
		goto tr18;
	goto tr0;
case 21:
	switch( (*p) ) {
		case 60: goto tr1;
		case 62: goto tr29;
	}
	goto tr0;
case 57:
	if ( (*p) == 60 )
		goto tr71;
	goto tr70;
case 22:
	switch( (*p) ) {
		case 34: goto tr26;
		case 39: goto tr26;
		case 47: goto tr30;
		case 60: goto tr25;
		case 95: goto tr24;
		case 101: goto tr31;
		case 125: goto tr24;
	}
	if ( (*p) > 90 ) {
		if ( 97 <= (*p) && (*p) <= 123 )
			goto tr24;
	} else if ( (*p) >= 33 )
		goto tr24;
	goto tr0;
case 23:
	switch( (*p) ) {
		case 34: goto tr26;
		case 39: goto tr26;
		case 60: goto tr25;
		case 95: goto tr24;
		case 101: goto tr32;
		case 125: goto tr24;
	}
	if ( (*p) > 90 ) {
		if ( 97 <= (*p) && (*p) <= 123 )
			goto tr24;
	} else if ( (*p) >= 33 )
		goto tr24;
	goto tr0;
case 24:
	switch( (*p) ) {
		case 34: goto tr26;
		case 39: goto tr26;
		case 60: goto tr25;
		case 95: goto tr24;
		case 115: goto tr33;
		case 125: goto tr24;
	}
	if ( (*p) > 90 ) {
		if ( 97 <= (*p) && (*p) <= 123 )
			goto tr24;
	} else if ( (*p) >= 33 )
		goto tr24;
	goto tr0;
case 25:
	switch( (*p) ) {
		case 34: goto tr26;
		case 39: goto tr26;
		case 60: goto tr25;
		case 95: goto tr24;
		case 105: goto tr34;
		case 125: goto tr24;
	}
	if ( (*p) > 90 ) {
		if ( 97 <= (*p) && (*p) <= 123 )
			goto tr24;
	} else if ( (*p) >= 33 )
		goto tr24;
	goto tr0;
case 26:
	switch( (*p) ) {
		case 34: goto tr26;
		case 39: goto tr26;
		case 58: goto tr35;
		case 60: goto tr25;
		case 95: goto tr24;
		case 125: goto tr24;
	}
	if ( (*p) > 90 ) {
		if ( 97 <= (*p) && (*p) <= 123 )
			goto tr24;
	} else if ( (*p) >= 33 )
		goto tr24;
	goto tr0;
case 27:
	switch( (*p) ) {
		case 34: goto tr26;
		case 39: goto tr26;
		case 60: goto tr25;
		case 95: goto tr24;
		case 123: goto tr24;
		case 125: goto tr24;
	}
	if ( (*p) > 90 ) {
		if ( 97 <= (*p) && (*p) <= 122 )
			goto tr36;
	} else if ( (*p) >= 33 )
		goto tr24;
	goto tr0;
case 28:
	switch( (*p) ) {
		case 34: goto tr26;
		case 39: goto tr26;
		case 60: goto tr25;
		case 62: goto tr37;
		case 95: goto tr24;
		case 123: goto tr24;
		case 125: goto tr24;
	}
	if ( (*p) > 90 ) {
		if ( 97 <= (*p) && (*p) <= 122 )
			goto tr36;
	} else if ( (*p) >= 33 )
		goto tr24;
	goto tr0;
case 29:
	switch( (*p) ) {
		case 34: goto tr26;
		case 39: goto tr26;
		case 60: goto tr25;
		case 95: goto tr24;
		case 115: goto tr38;
		case 125: goto tr24;
	}
	if ( (*p) > 90 ) {
		if ( 97 <= (*p) && (*p) <= 123 )
			goto tr24;
	} else if ( (*p) >= 33 )
		goto tr24;
	goto tr0;
case 30:
	switch( (*p) ) {
		case 34: goto tr26;
		case 39: goto tr26;
		case 60: goto tr25;
		case 95: goto tr24;
		case 105: goto tr39;
		case 125: goto tr24;
	}
	if ( (*p) > 90 ) {
		if ( 97 <= (*p) && (*p) <= 123 )
			goto tr24;
	} else if ( (*p) >= 33 )
		goto tr24;
	goto tr0;
case 31:
	switch( (*p) ) {
		case 34: goto tr26;
		case 39: goto tr26;
		case 58: goto tr40;
		case 60: goto tr25;
		case 95: goto tr24;
		case 125: goto tr24;
	}
	if ( (*p) > 90 ) {
		if ( 97 <= (*p) && (*p) <= 123 )
			goto tr24;
	} else if ( (*p) >= 33 )
		goto tr24;
	goto tr0;
case 32:
	switch( (*p) ) {
		case 34: goto tr26;
		case 39: goto tr26;
		case 60: goto tr25;
		case 95: goto tr24;
		case 123: goto tr24;
		case 125: goto tr24;
	}
	if ( (*p) > 90 ) {
		if ( 97 <= (*p) && (*p) <= 122 )
			goto tr41;
	} else if ( (*p) >= 33 )
		goto tr24;
	goto tr0;
case 33:
	switch( (*p) ) {
		case 32: goto tr14;
		case 34: goto tr26;
		case 39: goto tr26;
		case 47: goto tr42;
		case 60: goto tr25;
		case 62: goto tr43;
		case 95: goto tr24;
		case 123: goto tr24;
		case 125: goto tr24;
	}
	if ( (*p) < 33 ) {
		if ( 9 <= (*p) && (*p) <= 13 )
			goto tr14;
	} else if ( (*p) > 90 ) {
		if ( 97 <= (*p) && (*p) <= 122 )
			goto tr41;
	} else
		goto tr24;
	goto tr0;
case 34:
	switch( (*p) ) {
		case 34: goto tr26;
		case 39: goto tr26;
		case 60: goto tr25;
		case 62: goto tr44;
		case 95: goto tr24;
		case 125: goto tr24;
	}
	if ( (*p) > 90 ) {
		if ( 97 <= (*p) && (*p) <= 123 )
			goto tr24;
	} else if ( (*p) >= 33 )
		goto tr24;
	goto tr0;
case 58:
	switch( (*p) ) {
		case 34: goto tr74;
		case 39: goto tr74;
		case 60: goto tr75;
		case 95: goto tr73;
		case 125: goto tr73;
	}
	if ( (*p) > 90 ) {
		if ( 97 <= (*p) && (*p) <= 123 )
			goto tr73;
	} else if ( (*p) >= 33 )
		goto tr73;
	goto tr72;
case 35:
	switch( (*p) ) {
		case 34: goto tr46;
		case 39: goto tr46;
		case 60: goto tr47;
		case 95: goto tr45;
		case 125: goto tr45;
	}
	if ( (*p) > 90 ) {
		if ( 97 <= (*p) && (*p) <= 123 )
			goto tr45;
	} else if ( (*p) >= 33 )
		goto tr45;
	goto tr0;
case 36:
	switch( (*p) ) {
		case 32: goto tr48;
		case 45: goto tr49;
		case 47: goto tr28;
		case 60: goto tr1;
		case 62: goto tr20;
		case 95: goto tr49;
	}
	if ( (*p) < 65 ) {
		if ( 9 <= (*p) && (*p) <= 13 )
			goto tr48;
	} else if ( (*p) > 90 ) {
		if ( 97 <= (*p) && (*p) <= 122 )
			goto tr49;
	} else
		goto tr49;
	goto tr0;
case 37:
	switch( (*p) ) {
		case 32: goto tr48;
		case 45: goto tr49;
		case 47: goto tr28;
		case 60: goto tr1;
		case 95: goto tr49;
	}
	if ( (*p) < 65 ) {
		if ( 9 <= (*p) && (*p) <= 13 )
			goto tr48;
	} else if ( (*p) > 90 ) {
		if ( 97 <= (*p) && (*p) <= 122 )
			goto tr49;
	} else
		goto tr49;
	goto tr0;
case 38:
	switch( (*p) ) {
		case 45: goto tr49;
		case 60: goto tr1;
		case 61: goto tr50;
		case 95: goto tr49;
	}
	if ( (*p) < 65 ) {
		if ( 48 <= (*p) && (*p) <= 57 )
			goto tr49;
	} else if ( (*p) > 90 ) {
		if ( 97 <= (*p) && (*p) <= 122 )
			goto tr49;
	} else
		goto tr49;
	goto tr0;
case 39:
	switch( (*p) ) {
		case 32: goto tr51;
		case 34: goto tr52;
		case 39: goto tr52;
		case 60: goto tr1;
	}
	if ( 9 <= (*p) && (*p) <= 13 )
		goto tr51;
	goto tr0;
case 40:
	switch( (*p) ) {
		case 33: goto tr45;
		case 60: goto tr47;
		case 95: goto tr45;
		case 125: goto tr45;
	}
	if ( (*p) < 40 ) {
		if ( 35 <= (*p) && (*p) <= 38 )
			goto tr45;
	} else if ( (*p) > 90 ) {
		if ( 97 <= (*p) && (*p) <= 123 )
			goto tr45;
	} else
		goto tr45;
	goto tr0;
case 41:
	switch( (*p) ) {
		case 34: goto tr46;
		case 39: goto tr46;
		case 47: goto tr53;
		case 60: goto tr47;
		case 95: goto tr45;
		case 101: goto tr54;
		case 125: goto tr45;
	}
	if ( (*p) > 90 ) {
		if ( 97 <= (*p) && (*p) <= 123 )
			goto tr45;
	} else if ( (*p) >= 33 )
		goto tr45;
	goto tr0;
case 42:
	switch( (*p) ) {
		case 34: goto tr46;
		case 39: goto tr46;
		case 60: goto tr47;
		case 95: goto tr45;
		case 101: goto tr55;
		case 125: goto tr45;
	}
	if ( (*p) > 90 ) {
		if ( 97 <= (*p) && (*p) <= 123 )
			goto tr45;
	} else if ( (*p) >= 33 )
		goto tr45;
	goto tr0;
case 43:
	switch( (*p) ) {
		case 34: goto tr46;
		case 39: goto tr46;
		case 60: goto tr47;
		case 95: goto tr45;
		case 115: goto tr56;
		case 125: goto tr45;
	}
	if ( (*p) > 90 ) {
		if ( 97 <= (*p) && (*p) <= 123 )
			goto tr45;
	} else if ( (*p) >= 33 )
		goto tr45;
	goto tr0;
case 44:
	switch( (*p) ) {
		case 34: goto tr46;
		case 39: goto tr46;
		case 60: goto tr47;
		case 95: goto tr45;
		case 105: goto tr57;
		case 125: goto tr45;
	}
	if ( (*p) > 90 ) {
		if ( 97 <= (*p) && (*p) <= 123 )
			goto tr45;
	} else if ( (*p) >= 33 )
		goto tr45;
	goto tr0;
case 45:
	switch( (*p) ) {
		case 34: goto tr46;
		case 39: goto tr46;
		case 58: goto tr58;
		case 60: goto tr47;
		case 95: goto tr45;
		case 125: goto tr45;
	}
	if ( (*p) > 90 ) {
		if ( 97 <= (*p) && (*p) <= 123 )
			goto tr45;
	} else if ( (*p) >= 33 )
		goto tr45;
	goto tr0;
case 46:
	switch( (*p) ) {
		case 34: goto tr46;
		case 39: goto tr46;
		case 60: goto tr47;
		case 95: goto tr45;
		case 123: goto tr45;
		case 125: goto tr45;
	}
	if ( (*p) > 90 ) {
		if ( 97 <= (*p) && (*p) <= 122 )
			goto tr59;
	} else if ( (*p) >= 33 )
		goto tr45;
	goto tr0;
case 47:
	switch( (*p) ) {
		case 34: goto tr46;
		case 39: goto tr46;
		case 60: goto tr47;
		case 62: goto tr60;
		case 95: goto tr45;
		case 123: goto tr45;
		case 125: goto tr45;
	}
	if ( (*p) > 90 ) {
		if ( 97 <= (*p) && (*p) <= 122 )
			goto tr59;
	} else if ( (*p) >= 33 )
		goto tr45;
	goto tr0;
case 48:
	switch( (*p) ) {
		case 34: goto tr46;
		case 39: goto tr46;
		case 60: goto tr47;
		case 95: goto tr45;
		case 115: goto tr61;
		case 125: goto tr45;
	}
	if ( (*p) > 90 ) {
		if ( 97 <= (*p) && (*p) <= 123 )
			goto tr45;
	} else if ( (*p) >= 33 )
		goto tr45;
	goto tr0;
case 49:
	switch( (*p) ) {
		case 34: goto tr46;
		case 39: goto tr46;
		case 60: goto tr47;
		case 95: goto tr45;
		case 105: goto tr62;
		case 125: goto tr45;
	}
	if ( (*p) > 90 ) {
		if ( 97 <= (*p) && (*p) <= 123 )
			goto tr45;
	} else if ( (*p) >= 33 )
		goto tr45;
	goto tr0;
case 50:
	switch( (*p) ) {
		case 34: goto tr46;
		case 39: goto tr46;
		case 58: goto tr63;
		case 60: goto tr47;
		case 95: goto tr45;
		case 125: goto tr45;
	}
	if ( (*p) > 90 ) {
		if ( 97 <= (*p) && (*p) <= 123 )
			goto tr45;
	} else if ( (*p) >= 33 )
		goto tr45;
	goto tr0;
case 51:
	switch( (*p) ) {
		case 34: goto tr46;
		case 39: goto tr46;
		case 60: goto tr47;
		case 95: goto tr45;
		case 123: goto tr45;
		case 125: goto tr45;
	}
	if ( (*p) > 90 ) {
		if ( 97 <= (*p) && (*p) <= 122 )
			goto tr64;
	} else if ( (*p) >= 33 )
		goto tr45;
	goto tr0;
case 52:
	switch( (*p) ) {
		case 32: goto tr14;
		case 34: goto tr46;
		case 39: goto tr46;
		case 47: goto tr65;
		case 60: goto tr47;
		case 62: goto tr66;
		case 95: goto tr45;
		case 123: goto tr45;
		case 125: goto tr45;
	}
	if ( (*p) < 33 ) {
		if ( 9 <= (*p) && (*p) <= 13 )
			goto tr14;
	} else if ( (*p) > 90 ) {
		if ( 97 <= (*p) && (*p) <= 122 )
			goto tr64;
	} else
		goto tr45;
	goto tr0;
case 53:
	switch( (*p) ) {
		case 34: goto tr46;
		case 39: goto tr46;
		case 60: goto tr47;
		case 62: goto tr67;
		case 95: goto tr45;
		case 125: goto tr45;
	}
	if ( (*p) > 90 ) {
		if ( 97 <= (*p) && (*p) <= 123 )
			goto tr45;
	} else if ( (*p) >= 33 )
		goto tr45;
	goto tr0;
case 59:
	switch( (*p) ) {
		case 34: goto tr74;
		case 39: goto tr74;
		case 60: goto tr75;
		case 95: goto tr73;
		case 125: goto tr73;
	}
	if ( (*p) > 90 ) {
		if ( 97 <= (*p) && (*p) <= 123 )
			goto tr73;
	} else if ( (*p) >= 33 )
		goto tr73;
	goto tr72;
case 54:
	switch( (*p) ) {
		case 60: goto tr1;
		case 62: goto tr68;
	}
	goto tr0;
case 60:
	if ( (*p) == 60 )
		goto tr76;
	goto tr72;
case 55:
	switch( (*p) ) {
		case 60: goto tr1;
		case 62: goto tr69;
	}
	goto tr0;
	}

	tr0: cs = 0; goto f0;
	tr9: cs = 0; goto f2;
	tr16: cs = 0; goto f4;
	tr70: cs = 0; goto f9;
	tr72: cs = 0; goto f11;
	tr1: cs = 1; goto f1;
	tr71: cs = 1; goto f10;
	tr76: cs = 1; goto f13;
	tr2: cs = 2; goto f0;
	tr4: cs = 3; goto f0;
	tr5: cs = 4; goto f0;
	tr6: cs = 5; goto f0;
	tr7: cs = 6; goto f0;
	tr8: cs = 7; goto f0;
	tr3: cs = 8; goto f0;
	tr10: cs = 9; goto f0;
	tr11: cs = 10; goto f0;
	tr12: cs = 11; goto f0;
	tr13: cs = 12; goto f0;
	tr14: cs = 13; goto f3;
	tr17: cs = 14; goto f0;
	tr18: cs = 15; goto f0;
	tr22: cs = 16; goto f0;
	tr21: cs = 16; goto f6;
	tr23: cs = 17; goto f0;
	tr24: cs = 18; goto f0;
	tr37: cs = 18; goto f2;
	tr43: cs = 18; goto f4;
	tr26: cs = 19; goto f7;
	tr27: cs = 20; goto f0;
	tr28: cs = 21; goto f0;
	tr25: cs = 22; goto f1;
	tr30: cs = 23; goto f0;
	tr32: cs = 24; goto f0;
	tr33: cs = 25; goto f0;
	tr34: cs = 26; goto f0;
	tr35: cs = 27; goto f0;
	tr36: cs = 28; goto f0;
	tr31: cs = 29; goto f0;
	tr38: cs = 30; goto f0;
	tr39: cs = 31; goto f0;
	tr40: cs = 32; goto f0;
	tr41: cs = 33; goto f0;
	tr42: cs = 34; goto f3;
	tr45: cs = 35; goto f0;
	tr60: cs = 35; goto f2;
	tr66: cs = 35; goto f4;
	tr73: cs = 35; goto f11;
	tr46: cs = 36; goto f7;
	tr74: cs = 36; goto f12;
	tr48: cs = 37; goto f0;
	tr49: cs = 38; goto f0;
	tr51: cs = 39; goto f0;
	tr50: cs = 39; goto f6;
	tr52: cs = 40; goto f0;
	tr47: cs = 41; goto f1;
	tr75: cs = 41; goto f13;
	tr53: cs = 42; goto f0;
	tr55: cs = 43; goto f0;
	tr56: cs = 44; goto f0;
	tr57: cs = 45; goto f0;
	tr58: cs = 46; goto f0;
	tr59: cs = 47; goto f0;
	tr54: cs = 48; goto f0;
	tr61: cs = 49; goto f0;
	tr62: cs = 50; goto f0;
	tr63: cs = 51; goto f0;
	tr64: cs = 52; goto f0;
	tr65: cs = 53; goto f3;
	tr19: cs = 54; goto f3;
	tr15: cs = 55; goto f3;
	tr20: cs = 57; goto f5;
	tr29: cs = 57; goto f8;
	tr44: cs = 58; goto f0;
	tr67: cs = 59; goto f0;
	tr69: cs = 60; goto f0;
	tr68: cs = 60; goto f8;

f0:
#line 175 "parser.rl"
	{
    switch( cs ){
    case 0:
      if( parser->prev_state != 12 && parser->prev_state != 7 ){
        if( parser->echobuffer && (parser->prev_state != (esi_en_main +1)) && parser->prev_state != 60 ){
          // stream echobuffer
          esi_parser_echo_buffer( parser );
        }
//    printf( "[%d: %c]", cs, *p );
        // stream the current character
        esi_parser_echo_char( parser, *p );
      }
      // clear the echobuffer
      esi_parser_echobuffer_clear( parser );
      break;
    default:
      // append characters to echobuffer
      esi_parser_concat_to_echobuffer( parser, *p );
    }
    parser->prev_state = cs;
  }
	goto _again;
f1:
#line 175 "parser.rl"
	{
    switch( cs ){
    case 0:
      if( parser->prev_state != 12 && parser->prev_state != 7 ){
        if( parser->echobuffer && (parser->prev_state != (esi_en_main +1)) && parser->prev_state != 60 ){
          // stream echobuffer
          esi_parser_echo_buffer( parser );
        }
//    printf( "[%d: %c]", cs, *p );
        // stream the current character
        esi_parser_echo_char( parser, *p );
      }
      // clear the echobuffer
      esi_parser_echobuffer_clear( parser );
      break;
    default:
      // append characters to echobuffer
      esi_parser_concat_to_echobuffer( parser, *p );
    }
    parser->prev_state = cs;
  }
#line 85 "parser.rl"
	{
    parser->mark = p;
    //debug_string( "begin", p, 1 );
  }
	goto _again;
f9:
#line 175 "parser.rl"
	{
    switch( cs ){
    case 0:
      if( parser->prev_state != 12 && parser->prev_state != 7 ){
        if( parser->echobuffer && (parser->prev_state != (esi_en_main +1)) && parser->prev_state != 60 ){
          // stream echobuffer
          esi_parser_echo_buffer( parser );
        }
//    printf( "[%d: %c]", cs, *p );
        // stream the current character
        esi_parser_echo_char( parser, *p );
      }
      // clear the echobuffer
      esi_parser_echobuffer_clear( parser );
      break;
    default:
      // append characters to echobuffer
      esi_parser_concat_to_echobuffer( parser, *p );
    }
    parser->prev_state = cs;
  }
#line 89 "parser.rl"
	{
//    printf( "finish\n" );
  }
	goto _again;
f3:
#line 175 "parser.rl"
	{
    switch( cs ){
    case 0:
      if( parser->prev_state != 12 && parser->prev_state != 7 ){
        if( parser->echobuffer && (parser->prev_state != (esi_en_main +1)) && parser->prev_state != 60 ){
          // stream echobuffer
          esi_parser_echo_buffer( parser );
        }
//    printf( "[%d: %c]", cs, *p );
        // stream the current character
        esi_parser_echo_char( parser, *p );
      }
      // clear the echobuffer
      esi_parser_echobuffer_clear( parser );
      break;
    default:
      // append characters to echobuffer
      esi_parser_concat_to_echobuffer( parser, *p );
    }
    parser->prev_state = cs;
  }
#line 94 "parser.rl"
	{
    parser->tag_text = parser->mark+1;
    parser->tag_text_length = p - (parser->mark+1);
//    debug_string( "have esi start", parser->tag_text, parser->tag_text_length );
    parser->mark = p;
    //debug_string( "see_start_tag", p, 1 );
  }
	goto _again;
f8:
#line 175 "parser.rl"
	{
    switch( cs ){
    case 0:
      if( parser->prev_state != 12 && parser->prev_state != 7 ){
        if( parser->echobuffer && (parser->prev_state != (esi_en_main +1)) && parser->prev_state != 60 ){
          // stream echobuffer
          esi_parser_echo_buffer( parser );
        }
//    printf( "[%d: %c]", cs, *p );
        // stream the current character
        esi_parser_echo_char( parser, *p );
      }
      // clear the echobuffer
      esi_parser_echobuffer_clear( parser );
      break;
    default:
      // append characters to echobuffer
      esi_parser_concat_to_echobuffer( parser, *p );
    }
    parser->prev_state = cs;
  }
#line 102 "parser.rl"
	{
    //debug_string( "see_end_tag: before parsed esi tag", parser->tag_text, parser->tag_text_length );
    ltrim_pointer( &(parser->tag_text), p, &(parser->tag_text_length) );
    //debug_string( "see_end_tag: after parsed esi tag", parser->tag_text, parser->tag_text_length );
    parser->start_tag_handler( data, parser->tag_text, parser->tag_text_length, parser->attributes, parser->user_data );
    //debug_string( "see_end_tag: after start parsed esi tag", parser->tag_text, parser->tag_text_length );
    parser->end_tag_handler( data, parser->tag_text, parser->tag_text_length, parser->user_data );
    //debug_string( "see_end_tag: after end parsed esi tag", parser->tag_text, parser->tag_text_length );
    parser->tag_text = NULL;
    parser->tag_text_length = 0;
    parser->mark = p;
    //debug_string( "see_end_tag", p, 1 );
  }
	goto _again;
f5:
#line 175 "parser.rl"
	{
    switch( cs ){
    case 0:
      if( parser->prev_state != 12 && parser->prev_state != 7 ){
        if( parser->echobuffer && (parser->prev_state != (esi_en_main +1)) && parser->prev_state != 60 ){
          // stream echobuffer
          esi_parser_echo_buffer( parser );
        }
//    printf( "[%d: %c]", cs, *p );
        // stream the current character
        esi_parser_echo_char( parser, *p );
      }
      // clear the echobuffer
      esi_parser_echobuffer_clear( parser );
      break;
    default:
      // append characters to echobuffer
      esi_parser_concat_to_echobuffer( parser, *p );
    }
    parser->prev_state = cs;
  }
#line 116 "parser.rl"
	{
//    debug_string( "parsed esi tag", parser->tag_text, parser->tag_text_length );
    ltrim_pointer( &(parser->tag_text), p, &(parser->tag_text_length) );
    parser->start_tag_handler( data, parser->tag_text, parser->tag_text_length, parser->attributes, parser->user_data );
    parser->tag_text = NULL;
    parser->tag_text_length = 0;
  }
	goto _again;
f6:
#line 175 "parser.rl"
	{
    switch( cs ){
    case 0:
      if( parser->prev_state != 12 && parser->prev_state != 7 ){
        if( parser->echobuffer && (parser->prev_state != (esi_en_main +1)) && parser->prev_state != 60 ){
          // stream echobuffer
          esi_parser_echo_buffer( parser );
        }
//    printf( "[%d: %c]", cs, *p );
        // stream the current character
        esi_parser_echo_char( parser, *p );
      }
      // clear the echobuffer
      esi_parser_echobuffer_clear( parser );
      break;
    default:
      // append characters to echobuffer
      esi_parser_concat_to_echobuffer( parser, *p );
    }
    parser->prev_state = cs;
  }
#line 124 "parser.rl"
	{
    parser->attr_key = parser->mark;
    parser->attr_key_length = p - parser->mark;
    parser->mark = p;
    ltrim_pointer( &(parser->attr_key), p, &(parser->attr_key_length) );
//    debug_string( "\tattribute key", parser->attr_key, parser->attr_key_length );
    //debug_string( "see_attribute_key", p, 1 );
  }
	goto _again;
f7:
#line 175 "parser.rl"
	{
    switch( cs ){
    case 0:
      if( parser->prev_state != 12 && parser->prev_state != 7 ){
        if( parser->echobuffer && (parser->prev_state != (esi_en_main +1)) && parser->prev_state != 60 ){
          // stream echobuffer
          esi_parser_echo_buffer( parser );
        }
//    printf( "[%d: %c]", cs, *p );
        // stream the current character
        esi_parser_echo_char( parser, *p );
      }
      // clear the echobuffer
      esi_parser_echobuffer_clear( parser );
      break;
    default:
      // append characters to echobuffer
      esi_parser_concat_to_echobuffer( parser, *p );
    }
    parser->prev_state = cs;
  }
#line 133 "parser.rl"
	{
    ESIAttribute *attr;
    parser->attr_value = parser->mark;
    parser->attr_value_length = p - parser->mark;
    parser->mark = p;

    ltrim_pointer( &(parser->attr_value), p, &(parser->attr_value_length) );

    // allocate a new attribute
    attr = esi_attribute_new( parser->attr_key, parser->attr_key_length, 
                              parser->attr_value, parser->attr_value_length );
    if( parser->attributes ){
      parser->last->next = attr;
      parser->last = attr;
    }
    else{
      parser->last = parser->attributes = attr;
    }
//    debug_string( "\tattribute value", parser->attr_value, parser->attr_value_length );
    //debug_string( "see_attribute_value", p, 1 );
  }
	goto _again;
f4:
#line 175 "parser.rl"
	{
    switch( cs ){
    case 0:
      if( parser->prev_state != 12 && parser->prev_state != 7 ){
        if( parser->echobuffer && (parser->prev_state != (esi_en_main +1)) && parser->prev_state != 60 ){
          // stream echobuffer
          esi_parser_echo_buffer( parser );
        }
//    printf( "[%d: %c]", cs, *p );
        // stream the current character
        esi_parser_echo_char( parser, *p );
      }
      // clear the echobuffer
      esi_parser_echobuffer_clear( parser );
      break;
    default:
      // append characters to echobuffer
      esi_parser_concat_to_echobuffer( parser, *p );
    }
    parser->prev_state = cs;
  }
#line 155 "parser.rl"
	{
    parser->tag_text = parser->mark;
    parser->tag_text_length = p - parser->mark;
    parser->mark = p;
    ltrim_pointer( &(parser->tag_text), p, &(parser->tag_text_length) );
    parser->start_tag_handler( data, parser->tag_text, parser->tag_text_length, NULL, parser->user_data );
    //debug_string( "block_start_tag", p, 1 );
  }
	goto _again;
f2:
#line 175 "parser.rl"
	{
    switch( cs ){
    case 0:
      if( parser->prev_state != 12 && parser->prev_state != 7 ){
        if( parser->echobuffer && (parser->prev_state != (esi_en_main +1)) && parser->prev_state != 60 ){
          // stream echobuffer
          esi_parser_echo_buffer( parser );
        }
//    printf( "[%d: %c]", cs, *p );
        // stream the current character
        esi_parser_echo_char( parser, *p );
      }
      // clear the echobuffer
      esi_parser_echobuffer_clear( parser );
      break;
    default:
      // append characters to echobuffer
      esi_parser_concat_to_echobuffer( parser, *p );
    }
    parser->prev_state = cs;
  }
#line 164 "parser.rl"
	{
    parser->tag_text = parser->mark+2;
    parser->tag_text_length = p - (parser->mark+2);
    //printf( "mark: [%s], p: [%s], length: %d\n", parser->mark, p, parser->tag_text_length );
    parser->mark = p;
    //debug_string( "block_end_tag: before parsed esi tag", parser->tag_text, parser->tag_text_length );
    ltrim_pointer( &(parser->tag_text), p, &(parser->tag_text_length) );
    //debug_string( "block_end_tag: after parsed esi tag", parser->tag_text, parser->tag_text_length );
    parser->end_tag_handler( data, parser->tag_text, parser->tag_text_length, parser->user_data );
  }
	goto _again;
f10:
#line 175 "parser.rl"
	{
    switch( cs ){
    case 0:
      if( parser->prev_state != 12 && parser->prev_state != 7 ){
        if( parser->echobuffer && (parser->prev_state != (esi_en_main +1)) && parser->prev_state != 60 ){
          // stream echobuffer
          esi_parser_echo_buffer( parser );
        }
//    printf( "[%d: %c]", cs, *p );
        // stream the current character
        esi_parser_echo_char( parser, *p );
      }
      // clear the echobuffer
      esi_parser_echobuffer_clear( parser );
      break;
    default:
      // append characters to echobuffer
      esi_parser_concat_to_echobuffer( parser, *p );
    }
    parser->prev_state = cs;
  }
#line 85 "parser.rl"
	{
    parser->mark = p;
    //debug_string( "begin", p, 1 );
  }
#line 89 "parser.rl"
	{
//    printf( "finish\n" );
  }
	goto _again;
f11:
#line 175 "parser.rl"
	{
    switch( cs ){
    case 0:
      if( parser->prev_state != 12 && parser->prev_state != 7 ){
        if( parser->echobuffer && (parser->prev_state != (esi_en_main +1)) && parser->prev_state != 60 ){
          // stream echobuffer
          esi_parser_echo_buffer( parser );
        }
//    printf( "[%d: %c]", cs, *p );
        // stream the current character
        esi_parser_echo_char( parser, *p );
      }
      // clear the echobuffer
      esi_parser_echobuffer_clear( parser );
      break;
    default:
      // append characters to echobuffer
      esi_parser_concat_to_echobuffer( parser, *p );
    }
    parser->prev_state = cs;
  }
#line 102 "parser.rl"
	{
    //debug_string( "see_end_tag: before parsed esi tag", parser->tag_text, parser->tag_text_length );
    ltrim_pointer( &(parser->tag_text), p, &(parser->tag_text_length) );
    //debug_string( "see_end_tag: after parsed esi tag", parser->tag_text, parser->tag_text_length );
    parser->start_tag_handler( data, parser->tag_text, parser->tag_text_length, parser->attributes, parser->user_data );
    //debug_string( "see_end_tag: after start parsed esi tag", parser->tag_text, parser->tag_text_length );
    parser->end_tag_handler( data, parser->tag_text, parser->tag_text_length, parser->user_data );
    //debug_string( "see_end_tag: after end parsed esi tag", parser->tag_text, parser->tag_text_length );
    parser->tag_text = NULL;
    parser->tag_text_length = 0;
    parser->mark = p;
    //debug_string( "see_end_tag", p, 1 );
  }
#line 89 "parser.rl"
	{
//    printf( "finish\n" );
  }
	goto _again;
f13:
#line 175 "parser.rl"
	{
    switch( cs ){
    case 0:
      if( parser->prev_state != 12 && parser->prev_state != 7 ){
        if( parser->echobuffer && (parser->prev_state != (esi_en_main +1)) && parser->prev_state != 60 ){
          // stream echobuffer
          esi_parser_echo_buffer( parser );
        }
//    printf( "[%d: %c]", cs, *p );
        // stream the current character
        esi_parser_echo_char( parser, *p );
      }
      // clear the echobuffer
      esi_parser_echobuffer_clear( parser );
      break;
    default:
      // append characters to echobuffer
      esi_parser_concat_to_echobuffer( parser, *p );
    }
    parser->prev_state = cs;
  }
#line 85 "parser.rl"
	{
    parser->mark = p;
    //debug_string( "begin", p, 1 );
  }
#line 102 "parser.rl"
	{
    //debug_string( "see_end_tag: before parsed esi tag", parser->tag_text, parser->tag_text_length );
    ltrim_pointer( &(parser->tag_text), p, &(parser->tag_text_length) );
    //debug_string( "see_end_tag: after parsed esi tag", parser->tag_text, parser->tag_text_length );
    parser->start_tag_handler( data, parser->tag_text, parser->tag_text_length, parser->attributes, parser->user_data );
    //debug_string( "see_end_tag: after start parsed esi tag", parser->tag_text, parser->tag_text_length );
    parser->end_tag_handler( data, parser->tag_text, parser->tag_text_length, parser->user_data );
    //debug_string( "see_end_tag: after end parsed esi tag", parser->tag_text, parser->tag_text_length );
    parser->tag_text = NULL;
    parser->tag_text_length = 0;
    parser->mark = p;
    //debug_string( "see_end_tag", p, 1 );
  }
#line 89 "parser.rl"
	{
//    printf( "finish\n" );
  }
	goto _again;
f12:
#line 175 "parser.rl"
	{
    switch( cs ){
    case 0:
      if( parser->prev_state != 12 && parser->prev_state != 7 ){
        if( parser->echobuffer && (parser->prev_state != (esi_en_main +1)) && parser->prev_state != 60 ){
          // stream echobuffer
          esi_parser_echo_buffer( parser );
        }
//    printf( "[%d: %c]", cs, *p );
        // stream the current character
        esi_parser_echo_char( parser, *p );
      }
      // clear the echobuffer
      esi_parser_echobuffer_clear( parser );
      break;
    default:
      // append characters to echobuffer
      esi_parser_concat_to_echobuffer( parser, *p );
    }
    parser->prev_state = cs;
  }
#line 102 "parser.rl"
	{
    //debug_string( "see_end_tag: before parsed esi tag", parser->tag_text, parser->tag_text_length );
    ltrim_pointer( &(parser->tag_text), p, &(parser->tag_text_length) );
    //debug_string( "see_end_tag: after parsed esi tag", parser->tag_text, parser->tag_text_length );
    parser->start_tag_handler( data, parser->tag_text, parser->tag_text_length, parser->attributes, parser->user_data );
    //debug_string( "see_end_tag: after start parsed esi tag", parser->tag_text, parser->tag_text_length );
    parser->end_tag_handler( data, parser->tag_text, parser->tag_text_length, parser->user_data );
    //debug_string( "see_end_tag: after end parsed esi tag", parser->tag_text, parser->tag_text_length );
    parser->tag_text = NULL;
    parser->tag_text_length = 0;
    parser->mark = p;
    //debug_string( "see_end_tag", p, 1 );
  }
#line 133 "parser.rl"
	{
    ESIAttribute *attr;
    parser->attr_value = parser->mark;
    parser->attr_value_length = p - parser->mark;
    parser->mark = p;

    ltrim_pointer( &(parser->attr_value), p, &(parser->attr_value_length) );

    // allocate a new attribute
    attr = esi_attribute_new( parser->attr_key, parser->attr_key_length, 
                              parser->attr_value, parser->attr_value_length );
    if( parser->attributes ){
      parser->last->next = attr;
      parser->last = attr;
    }
    else{
      parser->last = parser->attributes = attr;
    }
//    debug_string( "\tattribute value", parser->attr_value, parser->attr_value_length );
    //debug_string( "see_attribute_value", p, 1 );
  }
#line 89 "parser.rl"
	{
//    printf( "finish\n" );
  }
	goto _again;

_again:
	if ( ++p != pe )
		goto _resume;
	_out: {}
	}
#line 351 "parser.rl"

  parser->cs = cs;

  if( cs != esi_start && cs != 0 ){

    if( !parser->overflow_data ){
      // recompute mark, tag_text, attr_key, and attr_value since they all exist within overflow_data
      int mark_offset = compute_offset( parser->mark, data );
      int tag_text_offset = compute_offset( parser->tag_text, data );
      int attr_key_offset = compute_offset( parser->attr_key, data );
      int attr_value_offset = compute_offset( parser->attr_value, data );
      //debug_string( "mark before move", parser->mark, 1 );

      parser->overflow_data = (char*)malloc( sizeof( char ) * length );
      memcpy( parser->overflow_data, data, length );
      parser->overflow_data_size = length;

      // in our new memory space mark will now be
      parser->mark = ( mark_offset >= 0 ) ? parser->overflow_data + mark_offset : NULL;
      parser->tag_text = ( tag_text_offset >= 0 ) ? parser->overflow_data + tag_text_offset : NULL;
      parser->attr_key = ( attr_key_offset >= 0 ) ? parser->overflow_data + attr_key_offset : NULL;
      parser->attr_value = ( attr_value_offset >= 0 ) ? parser->overflow_data + attr_value_offset : NULL;
      //if( parser->mark ){ debug_string( "mark after  move", parser->mark, 1 ); } else { printf( "mark is now empty\n" ); }
    }

  }else if( parser->overflow_data ){
    free( parser->overflow_data );
    parser->overflow_data = NULL;
    parser->overflow_data_size = 0;
  }

  return cs;
}
int esi_parser_finish( ESIParser *parser )
{
  
#line 1663 "parser.c"
#line 387 "parser.rl"
  return 0;
}

void esi_parser_start_tag_handler( ESIParser *parser, start_tag_cb callback )
{
  parser->start_tag_handler = callback;
}

void esi_parser_end_tag_handler( ESIParser *parser, end_tag_cb callback )
{
  parser->end_tag_handler = callback;
}
